package com.hu.bgp.server;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException;
import java.util.ArrayList;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;

import com.google.gwt.user.server.rpc.SerializationPolicy;
import com.google.gwt.user.server.rpc.SerializationPolicyLoader;
import com.hu.bgp.framework.GameState;
import com.hu.bgp.framework.clientapi.ClientGameContext;
import com.hu.bgp.framework.clientapi.ClientToServerMessage;
import com.hu.bgp.server.domain.Profile;
import com.hu.bgp.server.domain.Score;
import com.hu.bgp.shared.BoardGameService;
import com.hu.bgp.shared.ClientGameInstance;
import com.hu.bgp.shared.ClientGameInstanceCollection;
import com.hu.bgp.shared.ClientGameType;
import com.hu.bgp.shared.ClientGameTypeCollection;
import com.hu.bgp.shared.ClientScore;

import de.novanic.eventservice.service.RemoteEventServiceServlet;

/**
 * De 'main' servlet die binnenkomende berichten doorgeeft naar de juiste games
 * en de PlayerClient aanstuurt.
 * 
 * @author ejvos
 */
public class BoardGameServiceImpl extends RemoteEventServiceServlet implements BoardGameService
{
	public void init(ServletConfig config) throws ServletException
	{
		super.init(config);
		System.out.println("BoardGameServiceImpl.init");
		GameServerContext gsc = GameServerContext.getInstance(getServletContext());
	}

	public void handleMessage(ClientToServerMessage message)
	{
		System.out.println("BoardGameServiceImpl.handleMessage");
		GameServerContext gsc = GameServerContext.getInstance(getServletContext());
		Player player = gsc.getPlayerCollection().get(message.getFromUserUuid());
		player.getCurrentGameInstance().handleMessage(message, player);
	}

	public ClientGameContext getClientGameContext()
	{
		System.out.println("BoardGameServiceImpl.getClientGameContext");
		GameServerContext gsc = GameServerContext.getInstance(getServletContext());
		ClientGameContext result = null;
		Player player = gsc.getOrCreateCurrentPlayer(getRequest());
		GameInstance gameInstance = player.getCurrentGameInstance();
		if (gameInstance != null)
		{
			result = new ClientGameContext(player.getUuidString(), gameInstance.getGameContext().getGameDomain(), player.getDomain());
		}
		return result;
	}

	protected SerializationPolicy doGetSerializationPolicy(HttpServletRequest request, String moduleBaseURL, String strongName)
	{
		System.out.println("BoardGameServiceImpl.doGetSerializationPolicy");
		// The request can tell you the path of the web app relative to the
		// container root.
		String contextPath = request.getContextPath();

		String modulePath = null;
		if (moduleBaseURL != null)
		{
			try
			{
				modulePath = new URL(moduleBaseURL).getPath();
			}
			catch (MalformedURLException e)
			{
				e.printStackTrace();
			}
		}

		SerializationPolicy serializationPolicy = null;

		/*
		 * Check that the module path must be in the same web app as the servlet
		 * itself. If you need to implement a scheme different than this,
		 * override this method.
		 */
		if (modulePath == null || !modulePath.startsWith(contextPath))
		{
			String message = "ERROR: The module path requested, " + modulePath + ", is not in the same web application as this servlet, " + contextPath + ".  Your module may not be properly configured or your client and server code maybe out of date.";
			System.out.println(message);
		}
		else
		{
			// Strip off the context path from the module base URL. It should be
			// a strict prefix.
			String contextRelativePath = modulePath.substring(contextPath.length());

			String serializationPolicyFilePath = SerializationPolicyLoader.getSerializationPolicyFileName(contextRelativePath + strongName);

			// Open the RPC resource file and read its contents.
			GameServerContext gsc = GameServerContext.getInstance(getServletContext());
			File file = gsc.getResourcesFileByContextPath(serializationPolicyFilePath);
			InputStream is = null;
			try
			{
				is = new FileInputStream(file);
			}
			catch (FileNotFoundException e)
			{
				e.printStackTrace();
				// ignored, checks for null are performed
			}
			try
			{
				if (is != null)
				{
					try
					{
						serializationPolicy = SerializationPolicyLoader.loadFromStream(is, null);
					}
					catch (ParseException e)
					{
						System.out.println("ERROR: Failed to parse the policy file '" + serializationPolicyFilePath + "'");
						e.printStackTrace();
					}
					catch (IOException e)
					{
						System.out.println("ERROR: Could not read the policy file '" + serializationPolicyFilePath + "'");
						e.printStackTrace();
					}
				}
				else
				{
					String message = "ERROR: The serialization policy file '" + serializationPolicyFilePath + "' was not found; did you forget to include it in this deployment?";
					System.out.println(message);
				}
			}
			finally
			{
				if (is != null)
				{
					try
					{
						is.close();
					}
					catch (IOException e)
					{
						// Ignore this error
					}
				}
			}
		}

		return serializationPolicy;
	}

	public ClientGameTypeCollection getClientGameTypeCollection()
	{
		System.out.println("BoardGameServiceImpl.getClientGameTypeCollection");
		GameServerContext gsc = GameServerContext.getInstance(getServletContext());

		ClientGameTypeCollection result = new ClientGameTypeCollection();
		for (GameType gt : gsc.getGameTypeCollection())
		{
			if (gt.isActive())
				result.add(new ClientGameType(gt.getAlias(), gt.getDisplayName(), gt.getDescription()));
		}

		return result;
	}

	public ClientGameTypeCollection getClientGameTypeAdminCollection()
	{
		System.out.println("BoardGameServiceImpl.getClientGameTypeAdminCollection");
		GameServerContext gsc = GameServerContext.getInstance(getServletContext());

		ClientGameTypeCollection result = new ClientGameTypeCollection();
		for (GameType gt : gsc.getGameTypeCollection())
		{
			result.add(new ClientGameType(gt.getAlias(), gt.getDisplayName(), gt.getDescription(), gt.isActive()));
		}

		return result;
	}

	public void activateGame(ClientGameType gameType)
	{
		System.out.println("BoardGameServiceImpl.activateGame");
		GameServerContext gsc = GameServerContext.getInstance(getServletContext());
		GameType gt = gsc.getGameTypeCollection().getByAlias(gameType.getAlias());
		if (!gt.isActive())
		{
			gt.activate();
		}
	}

	/**
	 * returnt null indien profile onbekend is.
	 */
	public String getProfileName()
	{
		System.out.println("BoardGameServiceImpl.getProfileName");
		GameServerContext gsc = GameServerContext.getInstance(getServletContext());
		String result = null;
		Profile profile = gsc.getOrCreateCurrentProfile(getRequest());
		if (profile != null)
		{
			result = profile.getName();
		}
		return result;
	}

	public void setProfileName(String profileName)
	{
		System.out.println("BoardGameServiceImpl.setProfileName");
		GameServerContext gsc = GameServerContext.getInstance(getServletContext());
		Profile profile = gsc.getOrCreateCurrentProfile(getRequest());
		if (profile != null)
		{
			profile.setName(profileName);
			profile.save(gsc.getPersistence());
		}
	}

	public ClientGameInstanceCollection getClientGameInstanceCollection(String gameTypeAlias)
	{
		System.out.println("BoardGameServiceImpl.getClientGameInstanceCollection");
		GameServerContext gsc = GameServerContext.getInstance(getServletContext());
		ClientGameInstanceCollection result = new ClientGameInstanceCollection();
		for (GameInstance instance : gsc.getGameTypeCollection().getByAlias(gameTypeAlias).getGameInstances().getAllInstances())
		{
			result.add(new ClientGameInstance(instance.getUuidString(), instance.getGameContext().getState().toString(), "" + instance.getGameContext().getPlayers().size(), instance.getStartDate().toString()));
		}
		return result;
	}

	public ClientGameInstance createNewGameInstance(String gameTypeAlias)
	{
		System.out.println("BoardGameServiceImpl.createNewGameInstance");
		GameServerContext gsc = GameServerContext.getInstance(getServletContext());
		GameType gameType = gsc.getGameTypeCollection().getByAlias(gameTypeAlias);
		GameInstance instance = new GameInstance(gameType, gsc.getOrCreateCurrentPlayer(getRequest()));
		gameType.getGameInstances().put(instance, GameState.INITIALIZING);
		return new ClientGameInstance(instance.getUuidString());
	}

	// TODO gameTypeAlias shouldn't be necessary
	public String joinGame(String gameTypeAlias, String gameInstanceId)
	{
		System.out.println("BoardGameServiceImpl.joinGame");
		GameServerContext gsc = GameServerContext.getInstance(getServletContext());
		GameType gameType = gsc.getGameTypeCollection().getByAlias(gameTypeAlias);
		GameInstance instance = gameType.getGameInstances().get(gameInstanceId);
		Player player = gsc.getOrCreateCurrentPlayer(getRequest());
		player.joinGame(instance);
		// TODO what to return :)
		return "OKOK";
	}

	public ArrayList<ClientScore> getScores(String gameTypeAlias)
	{
		System.out.println("BoardGameServiceImpl.getScores");
		GameServerContext gsc = GameServerContext.getInstance(getServletContext());
		ArrayList<ClientScore> result = new ArrayList<ClientScore>();
		Player player = gsc.getOrCreateCurrentPlayer(getRequest());
		for (Score score : player.getProfile().getScores(gsc.getPersistence(), gameTypeAlias))
		{
			result.add(new ClientScore("" + score.getId(), score.getScoreText()));
		}
		return result;
	}
}
